package com.atan.weblog.common.aop;

import com.atan.weblog.common.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MemberSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Random;
import java.util.UUID;

@Aspect
@Slf4j
@Component
public class ApiOperationAspect {

    /**
     * 以注解的方式配置切点
     */
    @Pointcut("@annotation(com.atan.weblog.common.aop.ApiOperationLog)")
    public void apiOperationLog() {}


    @Around("apiOperationLog()")
    public Object logApiOperation(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            //计算开始时间
            long startTime = System.currentTimeMillis();
            //使用MDC
            MDC.put("traceId", UUID.randomUUID().toString());
            //获取请求的类和方法以及入参还有注解描述
            String className = joinPoint.getTarget().getClass().getSimpleName();
            String methodName = joinPoint.getSignature().getName();
            Object[] args = joinPoint.getArgs();
            //将入参转JSON字符
            String argsString = JsonUtil.toJson(args);
            //获取注解信息
            String annotationInfo = getAnnotationInfo(joinPoint);
            // 打印请求相关参数
            log.info("====== 请求开始: [{}], 入参: {}, 请求类: {}, 请求方法: {} =================================== ",
                    annotationInfo, argsString, className, methodName);

            // 执行切点方法
            Object result = joinPoint.proceed();

            // 执行耗时
            long executionTime = System.currentTimeMillis() - startTime;

            // 打印出参等相关信息
            log.info("====== 请求结束: [{}], 耗时: {}ms, 出参: {} =================================== ",
                    annotationInfo, executionTime, JsonUtil.toJson(result));
            return result;
        }finally {
            MDC.clear();
        }
    }

    /**
     * 获取注解value值信息
     * @param joinPoint
     * @return
     */
    private String getAnnotationInfo(ProceedingJoinPoint joinPoint) {
        //获取签名
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        //使用签名获取当前方法
        Method method = signature.getMethod();
        //获取注解
        ApiOperationLog annotation = method.getAnnotation(ApiOperationLog.class);
        //返回注解描述属性值
        return annotation.description();
    }

}
